package entityopinions;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;

public class Cache<K, V> extends LinkedHashMap<K, V> {

    private final int capacity;
    
    private long accessCount = 0;
    
    private long hitCount = 0;
    
    private long hitCountMemory = 0;
    
    private Map<K, V> map;

    public Cache(String dir, int capacity) throws DatabaseException {
        this(new File(dir), capacity);
    }

    public Cache(File dir, int capacity) throws DatabaseException {
        super(capacity + 1, 1.1f, true);
        this.capacity = capacity;
        EnvironmentConfig envConfig = new EnvironmentConfig();
        envConfig.setTransactional(false);
        envConfig.setAllowCreate(true);
        Environment env = new Environment(dir, envConfig);
        DatabaseConfig dbConfig = new DatabaseConfig();
        dbConfig.setTransactional(false);
        dbConfig.setAllowCreate(true);
        dbConfig.setSortedDuplicates(false);
        final Database store = env.openDatabase(null, "cachedatabase", dbConfig);
        StoredClassCatalog catalog = new StoredClassCatalog(store);
        SerialBinding<K> keyBinding = new SerialBinding(catalog, ((K) (new Object())).getClass());
        SerialBinding<V> valueBinding = new SerialBinding(catalog, ((V) (new Object())).getClass());
        this.map = new StoredSortedMap<K, V>(store, keyBinding, valueBinding, true);
        Runtime.getRuntime().addShutdownHook( new Thread( ) {
           public void run() {
                       try {
                               store.close();
                               store.getEnvironment().sync();
                               store.getEnvironment().close();
                       } catch ( DatabaseException ex ) {
                               ex.printStackTrace();
                       }
           }
       });
    }

    public Cache getCache(){
        return this;
    }

    public V get(Object key) {
        accessCount++;
        if (containsKey(key)) {
            hitCount++;
            hitCountMemory++;
            V value = super.get(key);
            return value;
        } else if (map.containsKey(key)) {
            hitCount++;
            V value = map.get(key);
            super.put((K) key, value);
            return value;
        }
        V value = super.get(key);
        return value;
    }

    public V put(K key, V value) {
        map.put(key, value);
        super.put(key, value);
        return value;
    }

    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
        return size() > capacity;
    }

    public long getAccessCount() {
        return accessCount;
    }

    public long getHitCount() {
        return hitCount;
    }

    public long getHitCountMemory() {
        return hitCountMemory;
    }

    public static void main(String[] args) throws Exception{

        File f = new File("C:/Users/Diogo/Desktop/Cache");
        Cache cache = new Cache(f, 100);
    }

}
